﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HelpersDotNet.DomainDrivenDesign.Infrastructure.DomainBase
{
    public abstract class EntityBase : IEntity
    {
        #region IEntity Members

        private object _key;
        /// <summary>
        /// An <see cref="System.Object"/> that represents the
        /// primary identifier value for the class.
        /// </summary>
        public object Key
        {
            get { return _key; }
            internal set
            {
                if (value == null)
                    throw new ArgumentNullException("Key", "Key cannot be set to null.");
                _key = value;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Default Constructor
        /// </summary>
        protected EntityBase() : this(null) { }

        /// <summary>
        /// Overloaded Constructor
        /// </summary>
        /// <param name="key">An <see cref="System.Object"/> that
        /// represents the primary key identifier value for the Entity.</param>
        protected EntityBase(object key)
        {
            if (key == null)
                key = GenerateNewKey();

            Key = key;
        }

        #endregion

        #region Equality Test

        /// <summary>
        /// Determines whether the specified entity is equal to
        /// the current instance.
        /// </summary>
        /// <param name="entity">An <see cref="System.Object"/> that will
        /// be compared to the current instance.</param>
        /// <returns>True if the passed entity is equal to the
        /// current instance.</returns>
        public override bool Equals(object entity)
        {
            return entity != null &&
                entity is EntityBase
                && this == (EntityBase)entity;
        }

        /// <summary>
        /// Operator overload for determining equality.
        /// </summary>
        /// <param name="entity1">The first instance of 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="entity2">The second instance of
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if equal.</returns>
        public static bool operator ==(EntityBase entity1, EntityBase entity2)
        {
            if ((object)entity1 == null && (object)entity2 == null)
                return true;

            if ((object)entity1 == null || (object)entity2 == null)
                return false;

            if (entity1.Key != entity2.Key)
                return false;

            return true;
        }

        /// <summary>
        /// Operator overload for determining inequality.
        /// </summary>
        /// <param name="entity1">The first instance of 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="entity2">The second instance of
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if not equal.</returns>
        public static bool operator !=(EntityBase entity1, EntityBase entity2)
        {
            return !(entity1 == entity2);
        }

        #endregion

        public static object GenerateNewKey()
        {
            return Guid.NewGuid();
        }

        public override int GetHashCode()
        {
            if (_key != null)
                return _key.GetHashCode();
            else
                return 0;
        }

        public abstract void Validate();
    }
}
